package edu.kit.csl.pisa.io;

import java.text.SimpleDateFormat;
import java.util.Date;

/*
This file is part of the PISA Alignment Tool.

Copyright (C) 2013
Karlsruhe Institute of Technology
Cognitive Systems Lab (CSL)
Felix Stahlberg

PISA is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

PISA is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with PISA. If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * Singleton class for logging.
 */
public class Logger {

	/**
	 * Logging level for debug information.
	 */
	static public final int DEBUG = 1;
	
	/**
	 * Logging level for notices and general information.
	 */
	static public final int NOTICE = 2;
	
	/**
	 * Logging level for warnings.
	 */
	static public final int WARNING = 3;
	
	/**
	 * Logging level for errors.
	 */
	static public final int ERROR = 4;
	
	/**
	 * Logging for fatal errors. After fatal errors, the program execution
	 * is not possible anymore.
	 */
	static public final int FATAL_ERROR = 5;
	
	/*
	 * String identifier for log levels
	 */
	static private final String strings[] = {
		"ALL",
		"DEBUG",
		"INFO",
		"WARN",
		"ERROR",
		"FATAL"
		};
	
	/*
	 * Singleton instance.
	 */
	static private Logger log;
	
	/*
	 * TRUE if a fatal error was reported
	 * 
	 * @see #fatalError()
	 */
	private boolean fatalErrorRegistered;
	
	/*
	 * Logging level
	 */
	private int level;
	
	/*
	 * Date formatter
	 */
	private SimpleDateFormat formatter;
	
	/*
	 * Private constructor.
	 */
	private Logger() {
		fatalErrorRegistered = false;
		level = Logger.NOTICE;
		formatter = new SimpleDateFormat("HH:mm:ss");
	}
	
	/**
	 * Get logging singleton. If it does not exist yet, create it.
	 */
	static public Logger getSingleton() {
		if (log == null) {
			log = new Logger();
		}
		return log;
	}
	
	/**
	 * Log a fatal error.
	 * 
	 * @param msg logging message
	 */
	public void fatalError(String msg) {
		fatalErrorRegistered = true;
		log(msg, Logger.FATAL_ERROR);
	}
	
	/**
	 * Returns true if a fatal error was reported yet.
	 * 
	 * @return TRUE if {@link #fatalError(String)} was called already, FALSE
	 * 			otherwise
	 * @see #fatalError(String)
	 */
	public boolean isFatalErrorRegistered() {
		return fatalErrorRegistered;
	}
	
	/**
	 * Log a message on Logger.NOTICE level.
	 * 
	 * @param msg logging message
	 */
	public void notice(String msg) {
		log(msg, Logger.NOTICE);
	}
	
	/**
	 * Log a message on Logger.ERROR level.
	 * 
	 * @param msg logging message
	 */
	public void error(String msg) {
		log(msg, Logger.ERROR);
	}
	
	/**
	 * Log a message on Logger.WARNING level.
	 * 
	 * @param msg logging message
	 */
	public void warn(String msg) {
		log(msg, Logger.WARNING);
	}
	
	/**
	 * Log a message on Logger.DEBUG level.
	 * 
	 * @param msg logging message
	 */
	public void debug(String msg) {
		log(msg, Logger.DEBUG);
	}
	
	/**
	 * Log a message.
	 * 
	 * @param msg logging message
	 * @param level log level (one of the Logger.* constants)
	 */
	public void log(String msg, int level) {
		if (level >= this.level) {
			System.out.println(formatter.format(new Date())
					+ " " + strings[level] + ": " + msg);
		}
	}
	
	/**
	 * Set logging level. All message greater or equal the given level
	 * will be written.
	 * 
	 * @param int level the new logging level (one of the Logger.* constants)
	 */
	public void setLevel(int level) {
		this.level = level;
	}
	
	/**
	 * Set logging level using its name. All message greater or equal the 
	 * given level will be written. Do not change the level if the name
	 * does not match any level.
	 * 
	 * @param String level the name of the new level
	 */
	public void setLevel(String name) {
		for (int i = 0; i < strings.length; i++) {
			if (strings[i].equals(name)) {
				this.level = i;
				return;
			}
		}
	}
	
	/**
	 * Get the current logging level.
	 * 
	 * @return the current logging level (one of the Logger.* constants)
	 */
	public int getLevel() {
		return level;
	}
}
